const fs = require('fs-extra');
const path = require('path');
const { exec } = require('child_process');
const logger = require('../utils/logger');
const gitService = require('./gitService');
const historyService = require('./historyService');
const config = require('../config/default.json');
const PathUtils = require('../utils/pathUtils');
const OSUtils = require('../utils/osUtils');

class DeployService {
  constructor() {
    this.isDeploying = false;
    this.currentDeployId = null;
    this.currentProgress = 0;
    this.currentMessage = '';
    this.startTime = null; // Add startTime property
  }

  async deploy(deployId, pushData) {
    if (this.isDeploying) {
      throw new Error('已有部署任务正在进行中');
    }

    this.isDeploying = true;
    this.currentDeployId = deployId;
    this.currentProgress = 0;
    this.currentMessage = '开始部署...';
    this.startTime = new Date().toISOString(); // Set startTime when deploy starts

    try {
      // 设置开始时间
      await this.updateDeployStatus(deployId, 'running', '开始部署...', { 
        createdAt: this.startTime, // Use createdAt for history record
        progress: 10 
      });
      
      // 1. 拉取代码
      this.currentProgress = 20;
      this.currentMessage = '正在拉取代码...';
      await this.addLog(deployId, '正在拉取代码...');
      await gitService.pullCode(deployId, pushData);
      await this.addLog(deployId, '代码拉取完成');
      
      // 2. 安装依赖和构建
      this.currentProgress = 50;
      this.currentMessage = '正在构建项目...';
      await this.buildProject(deployId);
      
      // 3. 复制到部署目录
      this.currentProgress = 80;
      this.currentMessage = '正在部署文件...';
      await this.copyToDeployPath(deployId);
      
      // 4. 重启服务
      this.currentProgress = 90;
      this.currentMessage = '正在重启服务...';
      await this.restartService(deployId);
      
      // 完成部署
      this.currentProgress = 100;
      this.currentMessage = '部署完成';
      await this.updateDeployStatus(deployId, 'success', '部署完成', { 
        endTime: new Date().toISOString(),
        progress: 100 
      });
      
      return { success: true, message: '部署成功' };
      
    } catch (error) {
      logger.error('部署失败', { deployId, error: error.message });
      await this.updateDeployStatus(deployId, 'failed', `部署失败: ${error.message}`, { 
        endTime: new Date().toISOString(),
        progress: this.currentProgress 
      });
      throw error;
    } finally {
      this.isDeploying = false;
      this.currentDeployId = null;
      this.currentProgress = 0;
      this.currentMessage = '';
    }
  }

  async buildProject(deployId) {
    await this.addLog(deployId, '开始安装依赖和构建项目...');
    
    const repoPath = PathUtils.resolveConfigPath(config.git.localPath);
    
    // 检查是否存在package.json
    const packageJsonPath = PathUtils.join(repoPath, 'package.json');
    if (!(await fs.pathExists(packageJsonPath))) {
      await this.addLog(deployId, '未找到package.json，跳过依赖安装和构建');
      return;
    }

    for (let i = 0; i < config.build.commands.length; i++) {
      const command = config.build.commands[i];
      this.currentMessage = `正在执行构建命令: ${command}`;
      await this.addLog(deployId, `执行命令: ${command}`);
      
      try {
        const output = await this.execCommand(command, repoPath, config.build.timeout);
        // 只记录重要输出，避免日志过长
        const trimmedOutput = output.length > 500 ? 
          output.substring(0, 500) + '...(输出已截断)' : output;
        await this.addLog(deployId, `命令执行成功: ${trimmedOutput}`);
      } catch (error) {
        throw new Error(`构建命令失败 "${command}": ${error.message}`);
      }
    }
    
    await this.addLog(deployId, '依赖安装和项目构建完成');
  }

  async copyToDeployPath(deployId) {
    await this.addLog(deployId, '复制文件到部署目录...');
    
    const sourcePath = PathUtils.resolveConfigPath(config.git.localPath);
    const deployPath = PathUtils.resolveConfigPath(config.git.deployPath);
    
    try {
      // 确保部署目录存在
      await fs.ensureDir(deployPath);
      
      // 优先复制构建输出目录
      const possibleBuildPaths = ['dist', 'build', 'public'];
      let buildOutputPath = null;
      
      for (const buildDir of possibleBuildPaths) {
        const testPath = PathUtils.join(sourcePath, buildDir);
        if (await fs.pathExists(testPath)) {
          buildOutputPath = testPath;
          break;
        }
      }
      
      if (buildOutputPath) {
        await this.addLog(deployId, `复制构建输出: ${PathUtils.basename(buildOutputPath)}`);
        await fs.copy(buildOutputPath, deployPath, { overwrite: true });
      } else {
        // 如果没有构建输出目录，复制整个项目（排除不必要的文件）
        await this.addLog(deployId, '复制整个项目文件');
        await fs.copy(sourcePath, deployPath, {
          overwrite: true,
          filter: (src) => {
            const relativePath = PathUtils.relative(sourcePath, src);
            const excludePatterns = [
              'node_modules', '.git', 'temp', '.env', 
              '.DS_Store', 'Thumbs.db', '*.log'
            ];
            return !excludePatterns.some(pattern => 
              relativePath.includes(pattern) || relativePath.endsWith(pattern.replace('*', ''))
            );
          }
        });
      }
      
      await this.addLog(deployId, '文件复制完成');
    } catch (error) {
      throw new Error(`复制文件失败: ${error.message}`);
    }
  }

  async restartService(deployId) {
    if (!config.service.restartCommand || config.service.restartCommand.trim() === '') {
      await this.addLog(deployId, '未配置服务重启命令，跳过重启');
      return;
    }
    
    await this.addLog(deployId, `执行重启命令: ${config.service.restartCommand}`);
    
    try {
      const output = await this.execCommand(config.service.restartCommand, process.cwd(), 30000);
      const trimmedOutput = output.length > 200 ? 
        output.substring(0, 200) + '...(输出已截断)' : output;
      await this.addLog(deployId, `服务重启成功: ${trimmedOutput}`);
    } catch (error) {
      // 服务重启失败不应该导致整个部署失败
      await this.addLog(deployId, `服务重启失败: ${error.message}`);
      logger.warn('服务重启失败', { deployId, error: error.message });
    }
  }

  async execCommand(command, cwd, timeout = 60000) {
    const CommandUtils = require('../utils/commandUtils');
    
    try {
      const result = await CommandUtils.execute(command, {
        cwd: cwd || PathUtils.resolveConfigPath(config.git.localPath),
        timeout,
        encoding: 'utf8'
      });
      
      return result.stdout;
    } catch (error) {
      throw new Error(`命令执行失败: ${error.message}`);
    }
  }

  async updateDeployStatus(deployId, status, message, additionalData = {}) {
    try {
      await historyService.updateRecord(deployId, { 
        status, 
        message,
        ...additionalData
      });
    } catch (error) {
      logger.error('更新部署状态失败', { deployId, error: error.message });
    }
  }

  async addLog(deployId, message) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      message
    };
    
    logger.info(message, { deployId });
    
    try {
      await historyService.addLog(deployId, logEntry);
    } catch (error) {
      logger.error('添加部署日志失败', { deployId, error: error.message });
    }
  }

  getStatus() {
    return {
      isDeploying: this.isDeploying,
      currentDeployId: this.currentDeployId,
      progress: this.currentProgress,
      message: this.currentMessage,
      createdAt: this.startTime // Return createdAt (which is startTime)
    };
  }
}

module.exports = new DeployService();